<html>
<head>
	<style type="text/css">
		html, body {
			background-color: #886028;
			font-family: 'Sans Serif';
		}
		
		button#go, button#finalize {
			font-size: 1.3em;
			padding:5px;
			margin-right: 60px;
		}
		
		.left {
			float: left;
		}
		
		.option-list > div {
			margin-right: 40px;
		}
		
		.option-list::after {
			clear: both;
			content: "";
			display: table;
		}
		
		label, select {
			display: block;
			padding: 5 0px;
		}
		
		label > span {
			min-width: 140px;
			display: inline-block;
			font-weight: bold;
		}
		
		
		label > input {
			width: 70px;
			display: inline-block;
			text-align: right;
			padding: 3px;
		}
		
		.cost {
			text-align: right;
		}
		.avail{
			text-align: center;
		}
		.reroll {
			text-align: center;
		}
		.menu {
			
			
		}
		
		.item {
			padding: 5px;
		}
		
		
		.item-table {
			margin-top: 20px;
			border-collapse: collapse;
		}
		.item-table th {
			padding: 3px 10px;
			border: 1px solid black;
		}
		
		.item-table td {
			padding: 3px 10px;
		}
		.item-table tbody tr:nth-child(odd) {
			background-color: #997039;
		}
		
	
	</style>
	<script type="text/javascript">var module = {};</script>
	<script src="itemList.js"></script>
	
	<script type="text/javascript">
		/*
		art, gems, statues, etc.
		"mundane"
		attachment, ie. finger, shoulder, hat, etc.
		scrolls
		
		*/
	
		/*
		for(var m of module.exports.minor_item_list) {
			if(!module.exports.items[m]) console.log('missing:', m);
		}
		*/
		
		var prng_seed = Math.floor(Math.random() * 10000 + 10000);
		
		var wh = window.location.hash;
		var hash_opts = [];
		if(wh) {
			var params = wh.split('_');
			prng_seed = params[0];
			hash_opts = params[1].split('!');
		}
			
		
		function frand() {
			var x = Math.sin(prng_seed++) * 31337;
			return x - Math.floor(x);
		}
		
		
		function clone(obj) {
			var o = {};
			for(var k in obj) {
				var v = obj[k];
				
				if(typeof v == 'object') {
					if(v instanceof Array) o = [];
					o[k] = clone(v);
				}
				else {
					o[k] = v;
				}
			}
			return o;
		}
		
		
		var magic_ammo_rarity = {
			1: 'uncommon',
			2: 'rare',
			3: 'very rare',
		}
		var magic_weapon_rarity = {
			1: 'uncommon',
			2: 'rare',
			3: 'very rare',
		}
		var magic_armor_rarity = {
			1: 'rare',
			2: 'very rare',
			3: 'legendary',
		}
		
		var armor_of_resistance_types = [
			"Acid",
			"Cold",
			"Fire",
			"Force",
			"Lightning",
			"Necrotic",
			"Poison",
			"Psychic",
			"Radiant",
			"Thunder",
		];
		
		var scroll_level_data = {
			0: {name: 'Cantrip', rarity: 'common', save_dc: 13, attack_bonus: 5},
			1: {name: '1st', rarity: 'common', save_dc: 13, attack_bonus: 5},
			2: {name: '2nd', rarity: 'uncommon', save_dc: 13, attack_bonus: 5},
			3: {name: '3rd', rarity: 'uncommon', save_dc: 15, attack_bonus: 7},
			4: {name: '4th', rarity: 'rare', save_dc: 15, attack_bonus: 7},
			5: {name: '5th', rarity: 'rare', save_dc: 17, attack_bonus: 9},
			6: {name: '6th', rarity: 'very rare', save_dc: 17, attack_bonus: 9},
			7: {name: '7th', rarity: 'very rare', save_dc: 18, attack_bonus: 10},
			8: {name: '8th', rarity: 'very rare', save_dc: 18, attack_bonus: 10},
			9: {name: '9th', rarity: 'legendary', save_dc: 19, attack_bonus: 11},
		};
		
		// make a list of 'any' ammos
		var any_ammo_list = [];
		for(var owi in module.exports.items) {
			var ow = module.exports.items[owi];
			if(ow.type == 'ammunition' && ow.magic_item && ow.any) {
				any_ammo_list.push(ow);
				delete module.exports.items[owi];
			}
		}
		
		// fill in all the ammo
		for(var owi in module.exports.items) {
			var ow = module.exports.items[owi];
			if(!(ow.type == 'ammunition' && ow.rarity == 'common' && !ow.magic_item)) continue;
			
			for(var b = 1; b <= 3; b++) {
				var nw = clone(ow);
				nw.name += ', +' + b;
				nw.id = owi + ', +' + b;
				nw.magic_item = true;
				nw.rarity = magic_ammo_rarity[b];
				nw.attack_bonus = b;
				nw.damage_bonus = b;
				
				module.exports.items[nw.id] = nw;
				module.exports.minor_item_list.push(nw.id);
			}
			
			// "any" ammos
			for(var aw of any_ammo_list) {
				var good = 0;
				if(aw.any == 'ammunition') good = 1;
						
				if(good == 1) {
					var nw = clone(aw);
					nw.id = aw.id+ ', ' + ow.id;
					nw.name = aw.name + ', ' + ow.name;
					module.exports.items[nw.id] = nw;
					module.exports.minor_item_list.push(nw.id);
				}
			}
		}
		
		// make a list of 'any' weapons
		var any_weapon_list = [];
		for(var owi in module.exports.items) {
			var ow = module.exports.items[owi];
			if(ow.type == 'weapon' && ow.magic_item && ow.any) {
				any_weapon_list.push(ow);
				delete module.exports.items[owi];
			}
		}
		
		
		// fill in all the weapons
		for(var owi in module.exports.items) {
			var ow = module.exports.items[owi];
			if(!(ow.type == 'weapon' && ow.rarity == 'mundane' && !ow.magic_item)) continue;
			
			// normal +1/2/3 magic weapons
			for(var b = 1; b <= 3; b++) {
				var nw = clone(ow);
				nw.name += ', +' + b;
				nw.id = owi + ', +' + b;
				nw.magic_item = true;
				nw.rarity = magic_weapon_rarity[b];
				nw.attack_bonus = b;
				nw.damage_bonus = b;
				
				module.exports.items[nw.id] = nw;
			}
			
			// "any" weapons
			for(var aw of any_weapon_list) {
				var good = 0;
				if(aw.any instanceof Array) {
					for(var aa of aw.any) {
						if(aw.any == 'weapon') good = 1;
						else if(aw.any == ow.weapon_style) good = 1;
						else if(aw.any == 'sword, slashing' && ow.weapon_style == 'sword') {
							if(ow.damage.indexOf('slashing') >= 0) good = 1; 
						}
						else continue;
						break;
					}
				}
				else if(aw.any == 'weapon') good = 1;
				else if(aw.any == ow.weapon_style) good = 1;
				else if(aw.any == 'sword, slashing' && ow.weapon_style == 'sword') {
					if(ow.damage.indexOf('slashing') >= 0) good = 1; 
				}
						
				if(good == 1) {
					var nw = clone(aw);
					nw.id = aw.id+ ', ' + ow.id;
					nw.name = aw.name + ', ' + ow.name;
					module.exports.items[nw.id] = nw;
				}
			}
		}
		
		// fill in all the armor
		for(var oai in module.exports.items) {
			var oa = module.exports.items[oai];
			if(!(oa.type == 'armor' && oa.rarity == 'mundane' &&  !oa.magic_item)) continue;
			
			for(var b = 1; b <= 3; b++) {
				var na = clone(oa);
				na.name += ', +' + b;
				na.id = oai + ', +' + b;
				na.magic_item = true;
				na.rarity = magic_armor_rarity[b];
				na.ac_bonus = b;
				module.exports.items[na.id] = na;
				
				// armor of resistance
				for(var dtype of armor_of_resistance_types) {
					var na = clone(oa);
					na.name += ' of Resistance, ' + dtype;
					na.id = oai + ' of resistance, ' + dtype.toLowerCase();
					na.magic_item = true;
					na.rarity = 'rare';
					na.ac_bonus = b;
					module.exports.items[na.id] = na;
				}
			}
			
			if((oa.subtype == 'medium' || oa.subtype == 'heavy') && oa.id != 'hide') {
				// mithral
				var na = clone(oa);
				na.name = 'Mithral ' + na.name;
				na.id += 'mithral ' + oai;
				na.magic_item = true;
				na.rarity = 'uncommon';
				na.mithral = true;
				na.min_str = '-';
				delete na.stealth;
				module.exports.items[na.id] = na;
				module.exports.minor_item_list.push(na.id);
				
				// adamantium
				var na = clone(oa);
				na.name = 'Adamantine ' + na.name;
				na.id += 'adamantine ' + oai;
				na.magic_item = true;
				na.rarity = 'uncommon';
				na.adamantium = true;
				module.exports.items[na.id] = na;
			}
		}
		
		// fill in the scrolls
		for(var spi in module.exports.spell_list) {
			var sp = module.exports.spell_list[spi];
			
			var ld = scroll_level_data[sp.level];
			var sc = {
				id: "scroll of " + sp.id,
				name: "Scroll of " + sp.name,
				type: "Scroll",
				level: sp.level,
				school: sp.school,
				magic_item: true,
				rarity: ld.rarity,
				attack_bonus: ld.attack_bonus,
				save_dc: ld.save_dc,
				consumable: true,
			};
			
			module.exports.items[sc.id] = sc;
			module.exports.minor_item_list.push(sc.id);
		}
		
		
		function $all(sel, n) {
			return (n || document).querySelectorAll(sel);
		}

		function $(sel, n) {
			return (n || document).querySelector(sel);
		}
		
		function $ce(tag, classes, content) {
			var n = document.createElement(tag);
			
			if(classes) {
				if(typeof classes == 'string') n.className = classes;
				else if(classes instanceof Array) n.classList = classes;
			}
			
			if(content) {
				if(typeof content == 'string') n.innerHTML = content;
				else if(typeof content == 'number') n.innerHTML = content + '';
				else n.appendChild(content);
			}
			
			return n;
		}
		
		function roll(n, d) {
			var s = 0;
			for(var i = 0; i < n; i++) s += Math.floor((frand() * d)) + 1;
			return s;
		}
		
		function makeControl(e) {
			var l = $ce('label');
			
			var c = $ce('input');
			c.type = e.getAttribute('type');
			c.value = e.innerHTML;
			c.id = e.getAttribute('cid');
			
			if(c.type == "checkbox") {
				if(e.innerHTML == "1") {
					c.checked = true;
				}
				
				l.appendChild(c);
				l.appendChild($ce('span', '', e.getAttribute('label')));
			}
			else {
				l.appendChild($ce('span', '', e.getAttribute('label')));
				l.appendChild(c);
			}
			
			e.parentNode.insertBefore(l, e);
			
			e.parentNode.removeChild(e);
		}
		
		
		function is_minor(x) {
			return module.exports.minor_item_list.indexOf(x) >= 0;
		}
		
		
		
		function getPrice(item, q) {
			var x;
			switch(item.rarity) {
				case 'mundane': x = q + 1; break;
				case 'common': x = q * 10; break;
				case 'uncommon': x = q * 100; break;
				case 'rare': x = q * 1000; break;
				case 'very rare': x = q * 10000; break;
				case 'legendary': x = (roll(1, 6) + q) * 25000; break;
				case 'artifact': x = (roll(2, 6) + q) * 250000; break;
			};
			
			if(item.consumable == true) x = Math.max(1, Math.floor((x / 2) + 0.5));
			
			return x;
		}
		
		function nfmt(s) {
			return String(s).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
		}
		
		function filterType(type, list, special) {
			for(var ind in list) {
				var i = list[ind];
				if(i.type == type) {
					special[type].push(i);
					list.splice(ind, 1);
				}
			}
		}
		
		
		function generateList(opts) {
				
			var cont = $('.item-list');
			cont.innerHTML = '';
			
			
			function qroll() {
				return roll(opts.qdice[0], opts.qdice[1]);
			}
			
			function filterItems(rarity, minor) {
				var o = [];
				for(var k in module.exports.items) {
					var i = module.exports.items[k];
					if(opts.exclude_cursed && i.cursed) continue;
					if(opts.include.PH == false && i.src == 'PH') continue;
					if(opts.include.DM == false && i.src == 'DM') continue;
					if(opts.include.XG == false && i.src == 'XG') continue;
					if(opts.include.EE == false && i.src == 'EE') continue;
					if(
						i.rarity == rarity  
						&& (is_minor(i.id) == minor)
						&& i.magic_item
					) {
						if(opts.exclude_pocket && i.pocket_dimension) continue;
					
						o.push(i);
					}
				}
				
				return o;
			}
			
			
			function addItem(item, list) {
				var c = $ce('tr', 'item');
				
				var qty = qroll();
				var price = 100 * opts.pmul;
				
				var n_ = $ce('td', 'name', item.name);
				var r_ = $ce('td', 'rarity', item.rarity);
				var q_ = $ce('td', 'avail', qroll());
				var p_ = $ce('td', 'cost', nfmt(getPrice(item, qty)));
				
				var rm = $ce('button', '', 'X');
				rm.addEventListener('click', function(e) {
					if(list.length == 0) {
						c.remove();
						return;
					};
					var ind = Math.floor(frand() * list.length);
					
					var it = list[ind];
					var q = qroll();
					
					n_.innerHTML = it.name;
					r_.innerHTML = it.rarity;
					q_.innerHTML = q;
					p_.innerHTML = nfmt(getPrice(it, q));
					
					list.splice(ind, 1);
				});
				
				c.appendChild(n_);
				c.appendChild(r_);
				c.appendChild(q_);
				c.appendChild(p_);
				c.appendChild(rm);
				
				c.appendChild($ce('td', 'reroll', rm))
				
				cont.appendChild(c);
			}
			
			
			var item_res = {};
			
			for(var sz in module.exports.standard_awards) {
				var z = module.exports.standard_awards[sz];
				
				for(var r in z) {
					var k = sz + '_' + r;
					var list = filterItems(r, sz == 'minor');
					item_res[k] = list;
					
					var amt = Math.floor((z[r][opts.CR] * opts.icmul) + .5);
					var chosen = [];
					var weapon_cnt = 0;
					var armor_cnt = 0;
					var scrolls_cnt = 0;
					
					var special = {
						weapon: [],
						armor: [],
						Scroll: [],
					};
					
					for(var n = 0; n < amt; n++) {
						if(list.length == 0) break;
						var ind = Math.floor(frand() * list.length);
						
						var it = list[ind];
						
						if(it.type == 'weapon') {
							if(++weapon_cnt > opts.max_weapons) {
								filterType('weapon', list, special);
								n--;
								continue;
							}
						}
						
						if(it.type == 'armor') {
							if(++armor_cnt > opts.max_armor) {
								filterType('armor', list, special);
								n--;
								continue;
							}
						}
						
						if(it.type == 'Scroll') {
							if(++scrolls_cnt > opts.max_scrolls) {
								filterType('Scroll', list, special);
								n--;
								continue;
							}
						}
						
						chosen.push(it);
						addItem(it, list, special);
						
						list.splice(ind, 1);
// 							console.log(n, ind, list);
					}
					
// 						console.log(sz, r, amt, list.length, chosen);
				} 
				
				
			}
		}
		
		
		window.addEventListener("load", function() {
			
			if(wh) {
				
				generateList({
					exclude_pocket: hash_opts[0] == 1,
					max_weapons: hash_opts[1]|0,
					max_armor:   hash_opts[2]|0,
					max_scrolls: hash_opts[3]|0,
					icmul: hash_opts[4]|0,
					pmul:  hash_opts[5]|0,
					qdice: hash_opts[6].split('d'),
					CR:    hash_opts[7]|0,
				});
			
				$('.menu').remove();
				$all('.reroll').forEach(function(x) { x.remove() });
				
				return;
			}
			
			
			$all('control').forEach(makeControl);
			
			
			$('#finalize').addEventListener('click', function(e) {
				$('.menu').remove();
				$all('.reroll').forEach(function(x) { x.remove() });
			});
			
			$('#go').addEventListener('click', function(e) {
				e.preventDefault();
				
				$('#finalize').style.display = 'inline-block';
				
				var prng_seed_orig = prng_seed;
				
// 				var raw = $('#item-count').value.toLowerCase();
// 				var [n,d] = raw.split('d');
				
				/* for checking the dice algorithm
				var o = {};
				for(var i = 0; i < n+2; i ++) o[i] = 0;
				for(var i = 0; i < 1000000; i ++){
					o[roll(n,d)]++;
				}
				console.log(o);
				*/
				
				var CRn = $('#tier');
				
				var o = {
					exclude_pocket: $('#exclude-pockets').checked,
					exclude_cursed: $('#exclude-cursed').checked,
					max_weapons: parseFloat($('#max-weapons').value),
					max_armor: parseFloat($('#max-armor').value),
					max_scrolls: parseFloat($('#max-scrolls').value),
					icmul: parseFloat($('#item-count').value),
					pmul: parseFloat($('#price-mul').value),
					qdice: $('#avail-dice').value.split('d'),
					CR: CRn.selectedOptions[0].value - 1,
					include: {
						PH: $('#include-PH').checked,
						DM: $('#include-DM').checked,
						XG: $('#include-XG').checked,
						EE: $('#include-EE').checked,
					},
				};
				
				generateList(o);
				
// 				window.location.hash = prng_seed_orig + '_' 
// 					+ (o.exclude_pocket ? '1' : '0') + '!'
			})
			
		});
		
		
	</script>
</head>
<body>
	<div class="menu">
		<select id="tier">
			<option value="1">Tier 1:  1-4</option>
			<option value="2" selected>Tier 2:  5-10</option>
			<option value="3">Tier 3: 11-16</option>
			<option value="4">Tier 4: 17-20</option>
		</select>
		
		<div class="option-list">
			<div class="left">
				<control cid="item-count" label="Item Count Mul.:" type="edit">1</control>
				<control cid="price-mul" label="Price Multiplier:" type="edit">1</control>
				<control cid="avail-dice" label="Avail/Price:" type="edit">1d6</control>
			<!--</div>
			<div class="left">-->
				<hr/>
				<label><span>Per Rarity:</span></label>
				<control cid="max-weapons" label="Max Weapons:" type="edit">2</control>
				<control cid="max-armor" label="Max Armor:" type="edit">2</control>
				<control cid="max-scrolls" label="Max Scrolls:" type="edit">2</control>
				
				<hr/>
				<control cid="exclude-pockets" label="Exclude Pocket Dimension" type="checkbox">1</control>
				<control cid="exclude-cursed" label="Exclude Cursed Items" type="checkbox">1</control>
				<control cid="include-PH" label="Include Player's Handbook" type="checkbox">1</control>
				<control cid="include-DM" label="Include DM's Guide" type="checkbox">1</control>
				<control cid="include-XG" label="Include Xanathar's Guide" type="checkbox">1</control>
				<control cid="include-EE" label="Include Elemental Evil" type="checkbox">0</control>
			</div>
		</div>
		
		<br/>
		<br/>
		<button id="go">Generate</button>
		<button id="finalize" style="display:none;">Finalize</button>
	</div>
	<table class="item-table" >
		<thead>
			<tr>
				<th>Item Name</th>
				<th>Rarity</th>
				<th>Qty.<br/>Available</th>
				<th>Price</th>
				<th class="reroll">Reroll</th>
			</tr>
		</thead>
		<tbody class="item-list"></tbody>
	</table>
	
</body>
</html>
